package edu.udo.sopra10.chaturaji.events;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import edu.udo.sopra10.chaturaji.entities.Game;
import edu.udo.sopra10.chaturaji.entities.Player;
import edu.udo.sopra10.chaturaji.entities.Square;
import edu.udo.sopra10.chaturaji.entities.transfer.Piece;

/**
 * Reset event that is invoked when major changes were made on the board and
 * the whole game state should be reset and reinterpreted.
 * 
 * @author Patrick Westerhoff
 */
public class BoardResetEvent extends ChaturajiEvent
{
	private static final long serialVersionUID = -2720039867231219998L;
	
	private boolean visualReset;
	private HashMap<Byte, Integer> scores;
	private HashMap<Byte, HashSet<Piece>> captured;
	private HashMap<Byte, String> playerNames;
	private HashMap<Byte, Player.Type> playerTypes;
	private Piece[][] board = new Piece[ 8 ][ 8 ];
	
	/**
	 * Constructs a move event based on the {@link Game} entity.
	 * 
	 * @param source the source object.
	 * @param game the game entity this event is based on.
	 * @param visualReset true if the event should be only processed visually.
	 */
	public BoardResetEvent ( Object source, Game game, boolean visualReset )
	{
		super( source );
		
		this.visualReset = visualReset;
		this.scores = new HashMap<Byte, Integer>( 4 );
		this.captured = new HashMap<Byte, HashSet<Piece>>( 4 );
		this.playerNames = new HashMap<Byte, String>( 4 );
		this.playerTypes = new HashMap<Byte, Player.Type>( 4 );
		
		// copy board data
		Square[][] board = game.getBoard();
		for ( int i = 0; i < 8; i++ )
		{
			for ( int j = 0; j < 8; j++ )
			{
				if ( board[i][j].getPiece() != null )
					this.board[i][j] = Piece.createFromEntity( board[i][j].getPiece() );
			}
		}
		
		// copy player data
		List<Player> players = game.getPlayers();
		for ( byte i = 0; i < 4; i++ )
		{
			Player player = players.get( i );
			playerNames.put( i, player.getName() );
			playerTypes.put( i, player.getType() );
			scores.put( i, players.get( i ).getScore() );
			
			HashSet<Piece> capturedPieces = new HashSet<Piece>( player.getCapturedPieces().size() );
			for ( edu.udo.sopra10.chaturaji.entities.pieces.Piece piece : player.getCapturedPieces() )
			{
				capturedPieces.add( Piece.createFromEntity( piece ) );
			}
			
			captured.put( i, capturedPieces );
		}
	}
	
	/**
	 * Constructs a move event based on the {@link Game} entity, that should be
	 * processed by all listeners.
	 * 
	 * @param source the source object.
	 * @param game the game entity this event is based on.
	 */
	public BoardResetEvent ( Object source, Game game )
	{
		this( source, game, false );
	}
	
	/**
	 * Returns true if the board reset should only processed visually but
	 * should not modify underlying data structures.
	 * 
	 * @return true if the event should be only processed visually.
	 */
	public boolean isVisualReset ()
	{
		return visualReset;
	}
	
	/**
	 * Returns the score of the given player.
	 * 
	 * @param playerId the player.
	 * @return the total score of the player.
	 */
	public Integer getScore ( byte playerId )
	{
		return scores.get( playerId );
	}
	
	/**
	 * Returns a set of captured pieces of the given player.
	 * 
	 * @param playerId the player.
	 * @return the set of captured players.
	 */
	public HashSet<Piece> getCaptured ( byte playerId )
	{
		return captured.get( playerId );
	}
	
	/**
	 * Returns the name of the given player.
	 * 
	 * @param playerId the player.
	 * @return the name of the player.
	 */
	public String getPlayerName ( byte playerId )
	{
		if ( playerTypes.get( playerId ) == Player.Type.EMAIL )
		{
			String name = playerNames.get( playerId );
			
			return name.substring( 0, name.indexOf( "<" ) );
		}
		else
			return playerNames.get( playerId );
	}
	
	/**
	 * Returns the player type of the given player.
	 * 
	 * @param playerId the player.
	 * @return the player type of the player.
	 */
	public Player.Type getPlayerType ( byte playerId )
	{
		return playerTypes.get( playerId );
	}
	
	/**
	 * Returns the current status of the board.
	 * 
	 * @return the board.
	 */
	public Piece[][] getBoard ()
	{
		return board;
	}
}